package com.cskaoyan.javase.oop1._11static._5exercise;

/**
 * 读程序题
 * 首先原则是:main方法入口方法,先从main方法开始看
 * 但是不要忘记了启动main方法触发类加载
 * 类加载的时机:
 *      1.启动main方法
 *      2.new对象
 *      3.访问静态成员
 *
 * 启动Demo类的main方法,触发Demo类的类加载
 * static成员变量需要在类加载时期开辟空间赋值
 *
 * 发现需要创建Cat对象,完成Demo类的类加载
 * 于是触发Cat类加载
 * 又发现要想完成Cat类加载,必须创建Dog对象
 * 于是触发Dog类加载
 * Dog类中没有静态成员,类加载不影响程序输出结果
 * 于是类加载家属,开始创建Dog对象
 * 于是控制台第一行会输出dog
 * Dog对象创建完毕,Cat类加载就结束了
 * 于是开始创建Cat对象
 * 去找Cat类的无参构造方法
 * 所以控制台第二行输出cat
 * Cat对象创建完毕后,Demo类的类加载才会结束
 * 到此为止,程序中的三个类都完成了类加载!!
 *
 * 所以总结:
 *      这个程序,类加载的顺序是从
 *      Demo类开始,接下来Cat,最后是Dog
 *      但是Dog最先完成类加载,Cat其次,最后完成类加载的是Demo
 *      这就是一个连环触发类加载的过程
 *
 * 类加载都完毕后,开始考虑启动main方法
 * 所以控制台第三行输出hello world
 *
 * 接下来执行创建Demo对象的语句
 * 在这个过程中,完全不需要考虑类加载了,因为三个类都已经完成类加载了
 * 直接找构造器,但是构造器不会立刻执行,而是从上到下按照代码顺序,执行成员变量的显式赋值
 *
 * 于是第四行应该输出dog
 * 最后输出demo
 *
 * 类加载的过程总体上分为三大部分:
 * 加载、连接、初始化
 * 初始化过程是最后一个过程，它的主要作用是用来执行和static相关的结构，比如：
 * 静态成员变量的初始化和赋值
 * 而只要完成加载、连接两个步骤，类的信息就已经读取进方法区了，这个时候就已经可以开始创建它的对象了、
 *
 * @since 11:40
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {

    // static int = 1;
    static Cat cat = new Cat();
    static {
        System.out.println("Demo类类加载了");
    }
    // int a = 10;
    Dog dog = new Dog();
    Dog dog2;

    public static void main(String[] args) {
        System.out.println("hello world!");
        Demo d = new Demo();
    }

    public Demo() {
        System.out.println("demo");
    }
}

class Cat {


    static Dog dog = new Dog(); //static3 int a = 10;
    static {
        System.out.println("Cat类类加载了");
    }

    public Cat() {
        System.out.println("cat");
    }
}

class Dog {

    static Demo demo = new Demo();
    static {
        System.out.println("Dog类类加载了");
    }
    public Dog() {
        System.out.println("dog");
    }
}
